﻿using CMS.AOP;
using CMS.Excep;
using CMS.Model;
using CMS.Utils;
using Microsoft.Data.Sqlite;

namespace CMS.DataAccess
{
    public class DbUpdater<T> where T:BaseModel, new()
    {
        protected List<IBeforeSaveOrDelAction<T>> beforeSaveActions = new List<IBeforeSaveOrDelAction<T>>();
        protected List<IBeforeSaveOrDelAction<T>> beforeDelActions = new List<IBeforeSaveOrDelAction<T>>();
        protected List<IAfterSaveAction<T>> afterActions = new List<IAfterSaveAction<T>>();

        public void RegBeforeSaveAction(IBeforeSaveOrDelAction<T> action)
        { 
            beforeSaveActions.Add(action);
        }
        public void RegAfterSaveAction(IAfterSaveAction<T> action)
        {
            afterActions.Add(action);
        }
        public void RegBeforeDelAction(IBeforeSaveOrDelAction<T> action)
        {
            beforeDelActions.Add(action);
        }
        public void Save(T data)
        {
            if (data == null) throw new MyNullException($"传入参数{typeof(T)}为空");
            var copy = MyUtils.JsonClone(data);
            try
            {
                if (data.Flag == 0)
                {
                    Insert(data);
                }
                else
                {
                    Update(data);
                }
                
            }
            catch (MyException ex)
            {
                MyUtils.RestoreValues(data, copy);
                throw ex;
            }
            catch (Exception ex)
            {
                MyUtils.RestoreValues(data, copy);
                throw ex;
            }
        }
        public void Delete(string pk)
        {
            if (pk == null) throw new MyNullException($"传入参数{typeof(T)}为空");
            var optUser = ServiceLoader.GetService<OptUser>();
            var dbInstance = ServiceLoader.GetService<DbInstance>();
            DbQuery<T> query = new DbQuery<T>();
            var data = query.Get(pk);
            data.Modifier = optUser.UserId;
            data.ModifyTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            foreach (var act in beforeSaveActions)
            {
                act.DoAction(data, null);
            }
            var sql = dbInstance.ToDeleteSql<T>(pk, out SqliteParameter parameter);
            var result = dbInstance.ExeSql(sql, parameter);
            if (result != 1) throw new MySqlException("删除失败");

        }
        private void Insert(T data)
        {
            var optUser = ServiceLoader.GetService<OptUser>();
            var dbInstance = ServiceLoader.GetService<DbInstance>();
            if (!String.IsNullOrWhiteSpace(data.Pk))
                throw new MyArgException("创建单据时主键应为空白");
            data.Pk = MyUtils.GeneratePk();
            data.Del = "N";
            data.Creator = optUser.UserId;
            data.CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            data.Flag = 1;
            data.Modifier = null;
            data.ModifyTime = null;
            foreach (var act in beforeSaveActions)
            {
                act.DoAction(null, data);
            }
            var sql = dbInstance.ToInsertSql(data,out SqliteParameter[] parameters);
            var result = dbInstance.ExeSql(sql, parameters);
            if (result != 1) throw new MySqlException("保存失败");
            foreach (var act in afterActions)
            {
                act.DoAction(data);
            }
        }
        private void Update(T data) 
        {
            var optUser = ServiceLoader.GetService<OptUser>();
            var dbInstance = ServiceLoader.GetService<DbInstance>();
            data.Modifier = optUser.UserId;
            data.ModifyTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            DbQuery<T> query = new DbQuery<T>();
            var oldData = query.Get(data.Pk);
            foreach (var act in beforeSaveActions)
            {
                act.DoAction(oldData, data);
            }
            var sql = dbInstance.ToUpdateSql(data, out SqliteParameter[] parameters);
            var result = dbInstance.ExeSql(sql, parameters);
            if (result != 1) throw new MySqlException("保存失败");
            data.Flag += 1;
            foreach (var act in afterActions)
            {
                act.DoAction(data);
            }
        }
    }
}
